package com.open.lock.config;

import com.open.lock.aspect.IdempotentAspect;
import com.open.lock.aspect.LockAspect;
import com.open.lock.component.CloudLock;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.config.ReplicatedServersConfig;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.redisson.connection.balancer.LoadBalancer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

/**
 * 分布式锁配置
 *
 * @author zhang kaichao
 */
@Configuration
@EnableConfigurationProperties(value = RedissonProperties.class)
@ConditionalOnClass(RedissonProperties.class)
public class RedissonConfig {

    @Autowired
    private RedissonProperties redissonProperties;

    @Bean
    @ConditionalOnMissingBean(CloudLock.class)
    public CloudLock cloudLock() {
        return new CloudLock();
    }

    @Bean
    @ConditionalOnMissingBean(LockAspect.class)
    public LockAspect lockAspect() {
        return new LockAspect();
    }

    @Bean
    @ConditionalOnMissingBean(IdempotentAspect.class)
    public IdempotentAspect idempotentAspect() {
        return new IdempotentAspect();
    }

    @Bean
    @ConditionalOnMissingBean(RedissonClient.class)
    public RedissonClient redissonClient() {
        Config config = new Config();
        try {
            config.setCodec((Codec) Class.forName(redissonProperties.getCodec()).newInstance());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        config.setLockWatchdogTimeout(redissonProperties.getLockWatchdogTimeout());
        RedissonProperties.MultipleProperties multiple = redissonProperties.getMultiple();
        switch (redissonProperties.getModel()) {
            case SINGLE:
                RedissonProperties.SingleProperties single = redissonProperties.getSingle();
                SingleServerConfig singleServerConfig = config.useSingleServer();
                singleServerConfig.setAddress(prefixAddress(single.getAddress()));
                singleServerConfig.setDatabase(single.getDatabase());
                singleServerConfig.setClientName(redissonProperties.getClientName());
                singleServerConfig.setPassword(redissonProperties.getPassword());
                singleServerConfig.setTimeout(redissonProperties.getTimeout());
                singleServerConfig.setConnectTimeout(redissonProperties.getConnectTimeout());
                singleServerConfig.setConnectionPoolSize(single.getConnectionPoolSize());
                singleServerConfig.setConnectionMinimumIdleSize(single.getConnectionMinimumIdleSize());
                break;
            case CLUSTER:
                ClusterServersConfig clusterServersConfig = config.useClusterServers();
                clusterServersConfig.setScanInterval(multiple.getScanInterval());
                clusterServersConfig.setReadMode(multiple.getReadMode());
                clusterServersConfig.setSlaveConnectionPoolSize(multiple.getSlaveConnectionPoolSize());
                clusterServersConfig.setSlaveConnectionMinimumIdleSize(multiple.getSlaveConnectionMinimumIdleSize());
                clusterServersConfig.setMasterConnectionPoolSize(multiple.getMasterConnectionPoolSize());
                clusterServersConfig.setMasterConnectionMinimumIdleSize(multiple.getMasterConnectionMinimumIdleSize());
                clusterServersConfig.setClientName(redissonProperties.getClientName());
                clusterServersConfig.setConnectTimeout(redissonProperties.getConnectTimeout());
                clusterServersConfig.setTimeout(redissonProperties.getTimeout());
                clusterServersConfig.setPassword(redissonProperties.getPassword());
                try {
                    clusterServersConfig.setLoadBalancer((LoadBalancer) Class.forName(multiple.getLoadBalancer()).newInstance());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                for (String nodeAddress : multiple.getNode()) {
                    clusterServersConfig.addNodeAddress(prefixAddress(nodeAddress));
                }
                break;
            case SENTINEL:
                SentinelServersConfig sentinelServersConfig = config.useSentinelServers();
                sentinelServersConfig.setMasterName(multiple.getMasterName());
                sentinelServersConfig.setReadMode(multiple.getReadMode());
                sentinelServersConfig.setScanInterval(multiple.getScanInterval());
                try {
                    sentinelServersConfig.setLoadBalancer((LoadBalancer) Class.forName(multiple.getLoadBalancer()).newInstance());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                for (String nodeAddress : multiple.getNode()) {
                    sentinelServersConfig.addSentinelAddress(prefixAddress(nodeAddress));
                }
                sentinelServersConfig.setSlaveConnectionMinimumIdleSize(multiple.getSlaveConnectionMinimumIdleSize());
                sentinelServersConfig.setSlaveConnectionPoolSize(multiple.getSlaveConnectionPoolSize());
                sentinelServersConfig.setMasterConnectionPoolSize(multiple.getMasterConnectionPoolSize());
                sentinelServersConfig.setMasterConnectionMinimumIdleSize(multiple.getMasterConnectionMinimumIdleSize());
                sentinelServersConfig.setDatabase(multiple.getDatabase());
                sentinelServersConfig.setClientName(redissonProperties.getClientName());
                sentinelServersConfig.setPassword(redissonProperties.getPassword());
                sentinelServersConfig.setTimeout(redissonProperties.getTimeout());
                sentinelServersConfig.setConnectTimeout(redissonProperties.getConnectTimeout());
                break;
            case MASTERSLAVE:
                MasterSlaveServersConfig masterSlaveServersConfig = config.useMasterSlaveServers();
                int index = 0;
                for (String nodeAddress : multiple.getNode()) {
                    if (index++ == 0) {
                        masterSlaveServersConfig.setMasterAddress(prefixAddress(nodeAddress));
                    } else {
                        masterSlaveServersConfig.addSlaveAddress(prefixAddress(nodeAddress));
                    }
                }
                masterSlaveServersConfig.setReadMode(multiple.getReadMode());
                try {
                    masterSlaveServersConfig.setLoadBalancer((LoadBalancer) Class.forName(multiple.getLoadBalancer()).newInstance());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                masterSlaveServersConfig.setSlaveConnectionMinimumIdleSize(multiple.getSlaveConnectionMinimumIdleSize());
                masterSlaveServersConfig.setSlaveConnectionPoolSize(multiple.getSlaveConnectionPoolSize());
                masterSlaveServersConfig.setMasterConnectionPoolSize(multiple.getMasterConnectionPoolSize());
                masterSlaveServersConfig.setMasterConnectionMinimumIdleSize(multiple.getMasterConnectionMinimumIdleSize());
                masterSlaveServersConfig.setTimeout(redissonProperties.getTimeout());
                masterSlaveServersConfig.setConnectTimeout(redissonProperties.getConnectTimeout());
                masterSlaveServersConfig.setDatabase(multiple.getDatabase());
                masterSlaveServersConfig.setClientName(redissonProperties.getClientName());
                masterSlaveServersConfig.setPassword(redissonProperties.getPassword());
                break;
            case REPLICATED:
                ReplicatedServersConfig replicatedServersConfig = config.useReplicatedServers();
                replicatedServersConfig.setScanInterval(multiple.getScanInterval());
                for (String nodeAddress : multiple.getNode()) {
                    replicatedServersConfig.addNodeAddress(prefixAddress(nodeAddress));
                }
                try {
                    replicatedServersConfig.setLoadBalancer((LoadBalancer) Class.forName(multiple.getLoadBalancer()).newInstance());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                replicatedServersConfig.setReadMode(multiple.getReadMode());
                replicatedServersConfig.setSlaveConnectionMinimumIdleSize(multiple.getSlaveConnectionMinimumIdleSize());
                replicatedServersConfig.setSlaveConnectionPoolSize(multiple.getSlaveConnectionPoolSize());
                replicatedServersConfig.setMasterConnectionPoolSize(multiple.getMasterConnectionPoolSize());
                replicatedServersConfig.setMasterConnectionMinimumIdleSize(multiple.getMasterConnectionMinimumIdleSize());
                replicatedServersConfig.setTimeout(redissonProperties.getTimeout());
                replicatedServersConfig.setConnectTimeout(redissonProperties.getConnectTimeout());
                replicatedServersConfig.setDatabase(multiple.getDatabase());
                replicatedServersConfig.setClientName(redissonProperties.getClientName());
                replicatedServersConfig.setPassword(redissonProperties.getPassword());
                break;
            default:
                break;

        }
        return Redisson.create(config);
    }

    private String prefixAddress(String address) {
        if (!StringUtils.isEmpty(address) && !address.startsWith("redis")) {
            return "redis://" + address;
        }
        return address;
    }


}
